#pragma once

#include <iostream>
#include "Connection.hpp"

class HandleConnection
{
public:
    HandleConnection(func_t func)
        : _func(func)
    {
    }

    // 处理普通fd的读事件
    void HandleReader(Connection *con)
    {
        errno = 0; // 错误码可能是上一个fd的
        int fd = con->SockFd();
        char buffer[1024];

        // 这里可能一次读取不完整用户发送的数据
        while (true)
        {
            ssize_t rdBytes = ::recv(fd, buffer, sizeof(buffer) - 1, 0);
            if (rdBytes > 0)
            {
                buffer[rdBytes] = 0;
                con->Inbuffer() += buffer;
                LOG(DEBUG, "inbuffer :\n%s", con->Inbuffer().c_str());
                continue;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    // 所有数据都被读取，读取结束
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 读取错误，可能是因为fd关心的事件错误，这里统一处理
                    con->_excepter(con);
                    return;
                }
            }
        }

        // 读取到的数据不一定使完整的信息，这里需要进行序列化和反序列化
        _func(con);
    }

    // 处理普通fd的写事件
    void HandleWriter(Connection *con)
    {
        errno = 0;

        while (true)
        {
            int wtBytes = ::send(con->SockFd(), con->Outbuffer().c_str(), con->Outbuffer().size(), 0);
            if (wtBytes > 0)
            {
                // 这里可能没有将outbuffer的内容全部写出
                // 1. 先将已写的内容从缓冲区中删除
                con->OutbufferRmove(wtBytes);

                if (con->OutbufferEmpty())
                    break; // 这里不是直接return，是因为还需要关闭写事件
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    // 缓冲区已被写满，需要等待

                    break; // 这里不是直接return，是因为还需要关闭写事件
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 写错误，可能是因为fd关心的事件错误，这里统一处理
                    con->_excepter(con);
                    return;
                }
            }
        }

        // 走到这里有两种情况：1. 缓冲区已满，需要由内核等待；2. 缓冲区为空，所有内容已写完，关闭写事件

        if (!con->OutbufferEmpty())
        {
            // 1. 缓冲区已满，需要由内核等待，设置写事件
            con->_R->EnableReadWrite(con->SockFd(), true, true);
        }
        else
        {
            // 2. 缓冲区为空，所有内容已写完，关闭写事件
            con->_R->EnableReadWrite(con->SockFd(), true, false);
        }
    }

    // 处理普通fd的异常事件
    void HandleExcepter(Connection *con)
    {
        errno = 0;
        // 1. 从epoll模型中删除对fd的关心
        // 2. 关闭fd
        // 3. 释放Connection对象
        LOG(DEBUG, "client quit, fd: %d, from %s:%d", con->SockFd(), con->_addr.IP().c_str(), con->_addr.Port());
        con->_R->RemoveConnection(con->SockFd());
    }

private:
    func_t _func; // 处理读取到的数据，进行序列化和反序列化
};